package com.arpa.oms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.arpa.core.web.Result;
import com.arpa.ntocc.common.common.cache.PartyCache;
import com.arpa.ntocc.common.common.cache.ShipmentCache;
import com.arpa.ntocc.common.common.exception.ServiceException;
import com.arpa.ntocc.common.common.util.UserUtil;
import com.arpa.oms.domain.dto.BatchAddGoodsDTO;
import com.arpa.oms.domain.dto.SaleItemDto;
import com.arpa.oms.domain.entity.OmsGoodsRelationRecord;
import com.arpa.oms.domain.entity.Sale;
import com.arpa.oms.domain.entity.SaleItem;
import com.arpa.oms.domain.vo.SaleItemVO;
import com.arpa.oms.mapper.SaleItemMapper;
import com.arpa.oms.service.IOmsGoodsRelationRecordService;
import com.arpa.oms.service.ISaleItemService;
import com.arpa.oms.service.ISaleService;
import com.arpa.wms.cache.ShopCache;
import com.arpa.wms.cache.UnitCache;
import com.arpa.wms.domain.consts.NumConst;
import com.arpa.wms.domain.entity.Goods;
import com.arpa.wms.domain.entity.GoodsUnit;
import com.arpa.wms.service.IGoodsService;
import com.arpa.wms.service.IGoodsUnitService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * OMS销售单明细 服务实现类
 * </p>
 *
 * @author LEO
 * @since 2020-10-22
 */
@Service
@Log4j2(topic = "business")
public class SaleItemServiceImpl extends ServiceImpl<SaleItemMapper, SaleItem> implements ISaleItemService {

    @Autowired
    private PartyCache partyCache;
    @Autowired
    @Lazy
    private IGoodsService goodsService;
    @Autowired
    private UnitCache unitCache;
    @Autowired
    @Lazy
    private ISaleService saleService;
    @Autowired
    private IGoodsUnitService goodsUnitService;
    @Autowired
    private ShipmentCache shipmentCache;
    @Autowired
    private IOmsGoodsRelationRecordService goodsRelationRecordService;
    @Autowired
    private ShopCache shopCache;

    /**
     * @param dto :
     * @description 查询可退销售明细单
     * @author xuyang
     * @date 2020/12/21 9:33
     **/
    @Override
    public List<SaleItemVO> findCanRefundItemList(SaleItemDto dto) {
        return this.baseMapper.findCanRefundItemList(dto);
    }

    /**
     * @description
     * 批量更新销售单明细信息
     * @author rfwang
     * @date 2021/8/5 9:34
     * @param dto:
     **/
    @Override
    public int batchUpdateItemInfo(SaleItemDto dto){
        return this.baseMapper.batchUpdateItemInfo(dto);
    }

    /**
     * 批量添加商品
     * @param dto
     */
    @Override
    public Result batchAddGoods(BatchAddGoodsDTO dto){
        //1.校验订单信息
        validateSalesInfo(dto);
        //2.添加商品明细
        batchAddSaleItems(dto);
        return Result.ok();
    }

    private void validateSalesInfo(BatchAddGoodsDTO dto) {

        if (dto == null ) {
            throw new ServiceException("批量添加商品信息不能为空，请确认");
        }
        List<Sale> saleList = dto.getSaleList();
        List<SaleItem> saleItemList = dto.getSaleItemList();
        if (IterUtil.isEmpty(saleList)) {
            throw new ServiceException("所选销售单信息为空，请确认");
        }
        if (IterUtil.isEmpty(saleItemList)) {
            throw new ServiceException("新增商品信息为空，请确认");
        }
        //1.检验所选销售单是否是同一个仓库和店铺的
        Sale sale = saleList.get(NumConst.NUM_ZERO);
        String shopCode = sale.getShopCode();
        String warehouseCode = sale.getWarehouseCode();
        List<Sale> saleListFilter = saleList.stream().filter(e -> shopCode.equals(e.getShopCode()) && warehouseCode.equals(e.getWarehouseCode()))
                .collect(Collectors.toList());
        if (saleList.size() != saleListFilter.size()) {
            throw new ServiceException("所选销售单店铺或者仓库不一致，请确认");
        }
    }

    @Transactional(rollbackFor = {Exception.class})
    public void batchAddSaleItems(BatchAddGoodsDTO dto) {
        List<SaleItem> saleItemList = dto.getSaleItemList();
        List<String> saleCodes = dto.getSaleList().stream().map(info -> {return info.getCode();}).collect(Collectors.toList());
        String shipmentCode = UserUtil.getLoginWarehouseCodeOrShipmentCode();
        String createBy = UserUtil.getCode();
        String createName = partyCache.translate(createBy);
        LocalDateTime now = LocalDateTime.now();
        saleItemList.stream().forEach(info -> {
            String goodCode = info.getGoodCode();
            Goods goods = goodsService.getOne(new LambdaQueryWrapper<Goods>().eq(Goods::getGoodCode, goodCode).eq(Goods::getShipmentCode,shipmentCode));
            //查询所选销售单下所有的销售明细
            List<SaleItem> saleItems = this.list(new LambdaQueryWrapper<SaleItem>().in(SaleItem::getSaleCode, saleCodes));
            Map<String, List<SaleItem>> stringMap = saleItems.stream().collect(Collectors.groupingBy(SaleItem::getSaleCode));
            for (Map.Entry<String,List<SaleItem>> entry : stringMap.entrySet()) {
                List<String> goodCodeList = entry.getValue().stream().map(item -> item.getGoodCode()).collect(Collectors.toList());
                if (goodCodeList.contains(goodCode)) {
                    //更新销售明细，数量加一
                    this.update(new LambdaUpdateWrapper<SaleItem>().eq(SaleItem::getSaleCode, entry.getKey())
                            .eq(SaleItem::getGoodCode,goodCode)
                            .setSql("plan_quantity = plan_quantity + 1")
                            .setSql("gift_quantity = gift_quantity + 1")
                            .setSql("plan_basic_quantity = plan_basic_quantity + unit_convert_quantity")
                            .set(SaleItem::getModifiedBy, createBy)
                            .set(SaleItem::getModifiedName, createName)
                            .set(SaleItem::getGmtModified, now));
                } else {
                    //新增一条商品明细
                    SaleItem saleItem = new SaleItem();
                    BeanUtil.copyProperties(goods,saleItem);
                    saleItem.setCode(IdUtil.simpleUUID());
                    saleItem.setSaleCode(entry.getKey());
                    saleItem.setGoodsCode(goods.getCode());
                    saleItem.setGoodsBarCode(goods.getBarCode());
                    saleItem.setGoodsName(goods.getName());
                    saleItem.setExpirationQuantity(goods.getQuality());
                    saleItem.setPlanQuantity(BigDecimal.ONE);
                    saleItem.setActualQuantity(BigDecimal.ONE);
                    saleItem.setPlanBasicQuantity(BigDecimal.ONE);
                    saleItem.setActualBasicQuantity(BigDecimal.ONE);
                    saleItem.setBasicUnit(goods.getUnitCode());
                    saleItem.setBasicUnitName(unitCache.translate(goods.getUnitCode()));
                    saleItem.setSaleUnit(goods.getUnitCode());
                    saleItem.setSaleUnitName(unitCache.translate(goods.getUnitCode()));
                    saleItem.setUnitConvertQuantity(BigDecimal.ONE);
                    saleItem.setCreatedBy(createBy);
                    saleItem.setCreatedName(createName);
                    saleItem.setGmtCreated(now);
                    saleItem.setModifiedBy(createBy);
                    saleItem.setModifiedName(createName);
                    saleItem.setGmtModified(now);
                    saleItem.setBatchAdd(NumConst.NUM_ONE);
                    this.save(saleItem);
                }
            }
        });
    }

    /**
     * @description
     * 查询商品关系列表
     * @author rfwang
     * @date 2021/8/12 14:00
     * @param dto:
     **/
    @Override
    public List<SaleItemVO> goodsRelationList(SaleItemDto dto){
        return this.baseMapper.goodsRelationList(dto).stream().peek(info -> {
            info.setShopCode(dto.getShopCode());
            info.setShopName(shopCache.translate(dto.getShopCode()));
            info.setPlatformCode(dto.getPlatformCode());
            info.setPlatformName(dto.getPlatformName());
        }).collect(Collectors.toList());
    }

    /**
     * @description
     * 汇总商品关系数量
     * @author rfwang
     * @date 2021/8/12 14:00
     * @param dto:
     **/
    @Override
    public SaleItemVO goodsRelationListSum(SaleItemDto dto){
        return this.baseMapper.goodsRelationListSum(dto);
    }

    /**
     * @description
     * 保存商品关系
     * @author rfwang
     * @date 2021/8/12 16:47
     * @param dtoList:
     **/
    @Override
    public Result saveGoodsRelation(List<SaleItemDto> dtoList){
        //1.参数校验
        validateGoodsRelation(dtoList);
        //2.更新销售单明细信息并生成商品关系记录信息
        updateSaleItemInfoAndgenerateRecord(dtoList);
        return Result.ok();
    }

    private void validateGoodsRelation(List<SaleItemDto> dtoList) {
        if (IterUtil.isEmpty(dtoList)) {
            throw new ServiceException("所选保存数据为空，请确认");
        }
        List<SaleItemDto> saleItemDto = dtoList.stream().filter(info -> StrUtil.isEmpty(info.getGoodCode())).collect(Collectors.toList());
        if (saleItemDto.size() > NumConst.NUM_ZERO) {
            throw new ServiceException("存在商品编码为空的数据，请确认");
        }
    }

    @Transactional(rollbackFor = {Exception.class})
    public void updateSaleItemInfoAndgenerateRecord(List<SaleItemDto> dtoList) {
        String shipmentCode = UserUtil.getLoginWarehouseCodeOrShipmentCode();
        String shipmentName = shipmentCache.translate(shipmentCode);
        String creator = UserUtil.getCode();
        String creatorName = partyCache.translate(creator);
        LocalDateTime now = LocalDateTime.now();
        SaleItemDto dto = dtoList.get(NumConst.NUM_ZERO);
        List<OmsGoodsRelationRecord> omsGoodsRelationRecordList = Lists.newArrayList();
        List<String> goodsCodes = dtoList.stream().map(e -> e.getGoodsCode()).collect(Collectors.toList());
        List<Goods> goodsList = goodsService.list(new LambdaQueryWrapper<Goods>().eq(Goods::getShipmentCode, shipmentCode)
                .in(Goods::getCode, goodsCodes));
        List<Map<String, Object>> unitMapList = goodsUnitService.findUnitByShipmentCode(shipmentCode);
        List<GoodsUnit> goodsUnitList = unitMapList.stream().map(e-> BeanUtil.mapToBean(e, GoodsUnit.class, false)).collect(Collectors.toList());
        Map<String, GoodsUnit> goodsUnitMap = goodsUnitList.stream().collect(Collectors.toMap(GoodsUnit::getCode, e -> e));
        List<String> saleCodes = saleService.list(new LambdaQueryWrapper<Sale>().eq(Sale::getShipmentCode, shipmentCode)
                .eq(Sale::getShopCode, dto.getShopCode()).eq(Sale::getPlatformCode, dto.getPlatformCode()))
                .stream().map(info -> info.getCode()).collect(Collectors.toList());
        Map<String,Goods> goodsMap = goodsList.stream().collect(Collectors.toMap(Goods::getCode, e -> e));
        dtoList.stream().forEach(info -> {
            Goods goods = MapUtil.get(goodsMap, info.getGoodsCode(), Goods.class);
            GoodsUnit goodsUnit = MapUtil.get(goodsUnitMap, goods.getUnitCode(), GoodsUnit.class);
            this.update(new LambdaUpdateWrapper<SaleItem>().eq(SaleItem::getOuterGoodsCode, info.getOuterGoodsCode())
                    .in(SaleItem::getSaleCode, saleCodes).set(SaleItem::getGoodsCode, goods.getCode())
                    .set(SaleItem::getGoodCode, goods.getGoodCode())
                    .set(SaleItem::getGoodsName, goods.getName())
                    .set(SaleItem::getGoodsBarCode, goods.getBarCode())
                    .set(SaleItem::getSpec, goods.getSpec())
                    .set(SaleItem::getExpirationQuantity, goods.getQuality())
                    .set(SaleItem::getBasicUnit, goodsUnit.getCode())
                    .set(SaleItem::getBasicUnitName, goodsUnit.getUnitName())
                    .set(SaleItem::getUnitConvertQuantity, BigDecimal.ONE)
                    .set(SaleItem::getSaleUnit, goodsUnit.getCode())
                    .set(SaleItem::getSaleUnitName, goodsUnit.getUnitName())
                    .set(SaleItem::getUnitPrice, goods.getDeliveryPrice())
                    .set(SaleItem::getTotalMoney, goods.getDeliveryPrice())
                    .setSql("discount_amount = amount_money + " + goods.getDeliveryPrice().negate())
                    .set(SaleItem::getModifiedBy, creator)
                    .set(SaleItem::getModifiedName, creatorName)
                    .set(SaleItem::getGmtModified, now));
            //生成商品关系记录
            OmsGoodsRelationRecord omsGoodsRelationRecord = new OmsGoodsRelationRecord();
            BeanUtil.copyProperties(info,omsGoodsRelationRecord,false);
            omsGoodsRelationRecord.setCode(IdUtil.simpleUUID());
            omsGoodsRelationRecord.setShipmentCode(shipmentCode);
            omsGoodsRelationRecord.setShipmentName(shipmentName);
            omsGoodsRelationRecord.setGoodCode(goods.getGoodCode());
            omsGoodsRelationRecord.setGoodsCode(goods.getCode());
            omsGoodsRelationRecord.setGoodsName(goods.getName());
            omsGoodsRelationRecord.setCreatedBy(creator);
            omsGoodsRelationRecord.setCreatedName(creatorName);
            omsGoodsRelationRecord.setGmtCreated(now);
            omsGoodsRelationRecordList.add(omsGoodsRelationRecord);
        });
        //新增商品关系记录
        goodsRelationRecordService.saveBatch(omsGoodsRelationRecordList);
    }

    /**
     * @param saleCodes:
     * @description 查询缺少商品信息的销售单号
     * @author rfwang
     * @date 2021/8/25 16:47
     **/
    @Override
    public List<String> getSaleCodelackGoodsInfo(List<String> saleCodes){
        return this.baseMapper.getSaleCodelackGoodsInfo(saleCodes);
    }


}
